﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace BrasilFramework.Controle.Silverlight.Comportamento
{
    internal class MouseWheelScroll
    {
        private Point currentPoint;
        private UIElement s_rootElement;

        public static void Ativar(Control elemento)
        {
            new MouseWheelScrollBehavior(elemento);
        }

        public static void Ativar(ComboBox elemento)
        {
            new MouseWheelScroll().AtivarComboBox(elemento);
        }

        private void AtivarComboBox(ComboBox elemento)
        {
            HtmlPage.Window.AttachEvent("DOMMouseScroll", mouse_WheelTurned);
            HtmlPage.Window.AttachEvent("onmousewheel", mouse_WheelTurned);
            HtmlPage.Document.AttachEvent("onmousewheel", mouse_WheelTurned);

            if (elemento == null)
                return;

            if (s_rootElement != null)
                s_rootElement.MouseMove -= rootElement_MouseMove;

            s_rootElement = elemento;
            s_rootElement.MouseMove += rootElement_MouseMove;
        }

        private void rootElement_MouseMove(object sender, MouseEventArgs e)
        {
            currentPoint = e.GetPosition(null);
        }

        private void mouse_WheelTurned(Object sender, HtmlEventArgs args)
        {
            double delta = 0;
            ScriptObject e = args.EventObject;

            if (e.GetProperty("wheelDelta") != null) // IE and Opera 
            {
                delta = ((double) e.GetProperty("wheelDelta"));
                if (HtmlPage.Window.GetProperty("opera") != null)
                    delta = -delta;
            }
            else if (e.GetProperty("detail") != null) // Mozilla and Safari 
            {
                delta = -((double) e.GetProperty("detail"));
            }

            if (delta != 0)
            {
                args.PreventDefault();
                e.SetProperty("returnValue", false);

                IEnumerable<UIElement> elements = VisualTreeHelper.FindElementsInHostCoordinates(currentPoint,
                                                                                                 s_rootElement);
                foreach (UIElement element in elements)
                {
                    AutomationPeer automationPeer = FrameworkElementAutomationPeer.FromElement(element) ??
                                                    FrameworkElementAutomationPeer.CreatePeerForElement(element);

                    if (automationPeer == null) continue;

                    bool ctrlKey = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control;

                    // note: TextBoxAutomationPeer does not implement IScrollProvider 
                    var scrollProvider = automationPeer.GetPattern(PatternInterface.Scroll) as IScrollProvider;
                    if (scrollProvider != null)
                    {
                        ScrollAmount scrollAmount = ScrollAmount.NoAmount;
                        if (delta < 0)
                            scrollAmount = ScrollAmount.SmallIncrement;
                        else if (delta > 0)
                            scrollAmount = ScrollAmount.SmallDecrement;

                        if (scrollProvider.HorizontallyScrollable && ctrlKey)
                        {
                            scrollProvider.Scroll(scrollAmount, ScrollAmount.NoAmount);

                            break;
                        }

                        if (scrollProvider.VerticallyScrollable)
                        {
                            scrollProvider.Scroll(ScrollAmount.NoAmount, scrollAmount);

                            break;
                        }
                    }
                }
            }
        }
    }

    internal class MouseWheelScrollBehavior
    {
        private readonly Control controle;

        public MouseWheelScrollBehavior(Control controle)
        {
            this.controle = controle;
            AssociarEvento();
        }

        private AutomationPeer Peer { get; set; }

        protected void AssociarEvento()
        {
            Peer = FrameworkElementAutomationPeer.FromElement(controle) ??
                   FrameworkElementAutomationPeer.CreatePeerForElement(controle);

            controle.MouseWheel += Controle_MouseWheel;
        }

        private void Controle_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            controle.Focus();

            int direction = Math.Sign(e.Delta);

            ScrollAmount scrollAmount =
                (direction < 0) ? ScrollAmount.SmallIncrement : ScrollAmount.SmallDecrement;

            if (Peer != null)
            {
                var scrollProvider =
                    Peer.GetPattern(PatternInterface.Scroll) as IScrollProvider;

                bool shiftKey = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;

                if (scrollProvider != null && scrollProvider.VerticallyScrollable && !shiftKey)
                    scrollProvider.Scroll(ScrollAmount.NoAmount, scrollAmount);
                else if (scrollProvider != null && scrollProvider.VerticallyScrollable && shiftKey)
                    scrollProvider.Scroll(scrollAmount, ScrollAmount.NoAmount);
            }
        }
    }
}